#include "tcp_server.h"
#include "app_control.h"
#include "stdio.h"
#if SERVER_SELECT == NETCONN
#include "lwip/opt.h"
#include "lwip/sys.h"
#include "lwip/api.h"

static void tcpecho_thread(void *arg)
{
	struct netconn *conn, *newconn;
	err_t err;
	LWIP_UNUSED_ARG(arg);
	/* Create a new connection identifier. */
	/* Bind connection to well known port number 7. */
	#if LWIP_IPV6
	conn = netconn_new(NETCONN_TCP_IPV6);
	netconn_bind(conn, IP6_ADDR_ANY, 5002);
	#else /* LWIP_IPV6 */
	conn = netconn_new(NETCONN_TCP);
	netconn_bind(conn, IP_ADDR_ANY, 5002);
	#endif /* LWIP_IPV6 */
	LWIP_ERROR("tcpecho: invalid conn", (conn != NULL), return;);
	/* Tell connection to go into listening mode. */
	netconn_listen(conn);
	while(1)
	{
		/* Grab new connection. */
		err = netconn_accept(conn, &newconn);
		/*printf("accepted new connection %p\n", newconn);*/
		/* Process the new connection. */
		if (err == ERR_OK)
		{
			struct netbuf *buf;
			void *data;
			u16_t len;
			while((err = netconn_recv(newconn, &buf)) == ERR_OK)
			{
				/*printf("Recved\n");*/
				do
				{
					netbuf_data(buf, &data, &len);
					err= netconn_write(newconn, data, len, NETCONN_COPY);
					#if 0
					if (err != ERR_OK)
					{
						printf("tcpecho: netconn_write: error \"%s\"\n",lwip_strerr(err));
					}
					#endif
				}
				while(netbuf_next(buf) >= 0);
				netbuf_delete(buf);
			}
			/*printf("Got EOF, looping\n");*/
			/* Close connection and discard connection identifier. */
			netconn_close(newconn);
			netconn_delete(newconn);
		}
	}
}

static void tcpecho_init(void)
{
	sys_thread_new("tcpecho_thread", tcpecho_thread, NULL, 512, 4);
}

void server_init(void)
{
	tcpecho_init();
}

#elif SERVER_SELECT == Socket
#include "lwip/opt.h"
#include <lwip/sockets.h>
#include "lwip/sys.h"
#include "lwip/api.h"

#define PORT 5002
#define RECV_DATA (1024)

static void tcpecho_thread(void *arg)
{
	int sock = -1,connected;
	char *recv_data;
	struct sockaddr_in server_addr,client_addr;
	socklen_t sin_size;
	int recv_data_len;
	recv_data = (char *)pvPortMalloc(RECV_DATA);
	if(recv_data == NULL)
	{
		printf("No memory\n");
		goto __exit;
	}
	sock = socket(AF_INET, SOCK_STREAM, 0);
	if(sock < 0)
	{
		printf("Socket error\n");
		goto __exit;
	}
	server_addr.sin_family = AF_INET;
	server_addr.sin_addr.s_addr = inet_addr("192.168.1.92");
	server_addr.sin_port = htons(PORT);
	memset(&(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero));
	if(bind(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1)
	{
		printf("Unable to bind\n");
		goto __exit;
	}
	if(listen(sock, 5) == -1)
	{
		printf("Listen error\n");
		goto __exit;
	}
	while(1)
	{
		sin_size = sizeof(struct sockaddr_in);
		connected = accept(sock, (struct sockaddr *)&client_addr, &sin_size);
		if(connected < 0)
		{
			printf("accept error\n");
		}
		printf("new client connected from (%s, %d)\n",
		inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
		{
			int flag = 1;
			if(setsockopt(connected,
			IPPROTO_TCP,        /* set option at TCP level */
			TCP_NODELAY,        /* name of option */
			(void *) &flag,     /* the cast is historical cruft */
			sizeof(int)) == -1) /* length of option value */
			{
				printf("setsockopt error\n");
			}
		}
		while(1)
		{
			recv_data_len = recv(connected, recv_data, RECV_DATA, 0);
			if (recv_data_len <= 0)
				break;
			printf("recv %d len data\n",recv_data_len);
			write(connected,recv_data,recv_data_len);
		}
		if (connected >= 0)
			closesocket(connected);
		connected = -1;
	}
	__exit:
	if(sock >= 0) closesocket(sock);
	if(recv_data) free(recv_data);
}

static void tcpecho_init(void)
{
	sys_thread_new("tcpecho_thread", tcpecho_thread, NULL, 512, 4);
}

void server_init(void)
{
	tcpecho_init();
}

#elif SERVER_SELECT == RAW_API
#include "lwip/netif.h"
#include "lwip/ip.h"
#include "lwip/tcp.h"
#include "lwip/init.h"
#include "netif/etharp.h"
#include "lwip/udp.h"
#include "lwip/pbuf.h"
#include <string.h>

#define TCP_ECHO_PORT 5002

static err_t tcpecho_recv(void *arg,struct tcp_pcb *tpcb,struct pbuf *p,err_t err)
{
	if (p != NULL)
	{
		/* 更新窗口*/
		tcp_recved(tpcb, p->tot_len);
		/* 返回接收到的数据*/
		tcp_write(tpcb, p->payload, p->tot_len, 1);
		memset(p->payload, 0 , p->tot_len);
		pbuf_free(p);
	}
	else if (err == ERR_OK)
	{
		return tcp_close(tpcb);
	}
	return ERR_OK;
}

static err_t tcpecho_accept(void *arg,struct tcp_pcb *newpcb,err_t err)
{
	tcp_recv(newpcb, tcpecho_recv);
	return ERR_OK;
}

static void TCP_Echo_Init(void)
{
	struct tcp_pcb *pcb = NULL;
	/* 创建一个 TCP 控制块 */
	pcb = tcp_new();
	/* 绑定 TCP 控制块 */
	tcp_bind(pcb, IP_ADDR_ANY, TCP_ECHO_PORT);
	/* 进入监听状态 */
	pcb = tcp_listen(pcb);
	/* 处理连接 */
	tcp_accept(pcb, tcpecho_accept);
}

void server_init(void)
{
	TCP_Echo_Init();
}

#else
void server_init(void)
{
	
}

#endif
